package com.yy.wga.pay.service.third;

import com.alibaba.fastjson.JSONObject;
import com.yy.wga.common.core.dto.Result;
import com.yy.wga.common.core.exception.BusinessException;
import com.yy.wga.common.util.common.JsonUtils;
import com.yy.wga.common.util.common.StringUtils;
import com.yy.wga.pay.feign.api.WechatNotifyFeign;
import com.yy.wga.pay.feign.eunms.EWechatTradeState;
import com.yy.wga.pay.feign.request.third.WechatPayNotifyDecodeRequest;
import com.yy.wga.pay.feign.request.third.WechatPayNotifyOriginRequest;
import com.yy.wga.pay.feign.request.third.WechatRefundNotifyDecodeRequest;
import com.yy.wga.pay.feign.request.third.WechatTransferNotifyDecodeRequest;
import com.yy.wga.pay.service.client.WechatPayClient;
import com.yy.wga.pay.service.common.utils.WxAPIV3AesUtil;
import com.yy.wga.pay.service.manager.PayCallbackManagerService;
import com.yy.wga.pay.service.manager.PayRefundCallbackManagerService;
import com.yy.wga.pay.service.manager.TransferCallbackManagerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;

/**
 * 微信通知接口
 *
 * @author guochao
 * @date 2021/6/5 17:00
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/pay/third/wechat")
public class WechatNotifyController implements WechatNotifyFeign {
    
    private final PayCallbackManagerService payCallbackManagerService;
    private final TransferCallbackManagerService transferCallbackManagerService;
    private final PayRefundCallbackManagerService refundCallbackManagerService;
    private final WechatPayClient wechatPayClient;

    /**
     * 异步通知
     * @param mchId
     * @param request
     * @return
     */
    @PostMapping(value = "/pay/notify/{appKey}/{mchId}")
    public Result<Void> payNotify(@PathVariable(name = "mchId") String mchId,
                            @PathVariable(name = "appKey") String appKey,
                            @RequestBody WechatPayNotifyOriginRequest request)  {
        try {
            log.info("微信支付异步通知返回原始参数 " + JSONObject.toJSONString(request));
            if (!"TRANSACTION.SUCCESS".equalsIgnoreCase(request.getEventType())) {
                log.error("微信支付异步通知交易失败");
                return Result.success();
            }
            // 解密
            String apiV3Key = wechatPayClient.getApiV3Key();
            WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayNotifyOriginRequest.ResourceDto resource = request.getResource();
            String decryptToString = aesUtil.decryptToString(resource.getAssociatedData().getBytes(StandardCharsets.UTF_8), resource.getNonce().getBytes(StandardCharsets.UTF_8), resource.getCiphertext());
            log.info("微信支付异步通知返回解密参数 " + decryptToString);
            if (StringUtils.isBlank(decryptToString)) {
                throw new BusinessException("返回信息为空");
            }

            // 订单实体解析
            WechatPayNotifyDecodeRequest wechatPayNotifyDecodeRequest = JSONObject.parseObject(decryptToString, WechatPayNotifyDecodeRequest.class);
            // 支付中状态不处理
            if (!wechatPayNotifyDecodeRequest.getTradeState().equals(EWechatTradeState.USERPAYING.name())) {
                AppPayNotifyDTO appPayNotifyDTO = new AppPayNotifyDTO();
                appPayNotifyDTO.setAppKey(appKey);
                appPayNotifyDTO.setOutTradeNo(wechatPayNotifyDecodeRequest.getOutTradeNo());
                if (StringUtils.isNotBlank(wechatPayNotifyDecodeRequest.getSuccessTime())) {
                    appPayNotifyDTO.setSuccessTime(com.yy.wga.common.utils.date.DateUtils.strToDate(wechatPayNotifyDecodeRequest.getSuccessTime().replace("T"," ").split("\\+")[0], com.yy.wga.common.utils.date.DateUtils.DATE_TIME_PATTERN));
                }
                EWechatTradeState wechatTradeState = EWechatTradeState.getByType(wechatPayNotifyDecodeRequest.getTradeState());
                if (wechatTradeState == null) {
                    log.error("返回未知的订单状态:{}", JsonUtils.toJSONString(wechatPayNotifyDecodeRequest));
                } else {
                    appPayNotifyDTO.setTradeState(wechatTradeState.getPayStatus());
                    appPayNotifyDTO.setTransactionId(wechatPayNotifyDecodeRequest.getTransactionId());
                    payCallbackManagerService.payNotify(appPayNotifyDTO);
                }
            }
            return Result.success();
        } catch (Exception e) {
            log.error("微信支付接口API,异步通知处理异常", e);
        }
        return Result.fail();
    }

    /**
     * 异步通知
     * @param mchId
     * @param request
     * @return
     */
    @PostMapping(value = "/transfer/notify/{appKey}/{mchId}")
    public Result<Void> transferNotify(@PathVariable(name = "mchId") String mchId,
                                     @PathVariable(name = "appKey") String appKey,
                                     @RequestBody WechatPayNotifyOriginRequest request)  {
        try {
            log.info("微信商家转账异步通知返回原始参数 " + JSONObject.toJSONString(request));
            if (!"MCHTRANSFER.BILL.FINISHED".equalsIgnoreCase(request.getEventType())) {
                log.error("微信商家转账异步通知交易失败");
                return Result.success();
            }
            // 解密
            String apiV3Key = wechatPayClient.getApiV3Key();
            WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayNotifyOriginRequest.ResourceDto resource = request.getResource();
            String decryptToString = aesUtil.decryptToString(resource.getAssociatedData().getBytes(StandardCharsets.UTF_8), resource.getNonce().getBytes(StandardCharsets.UTF_8), resource.getCiphertext());
            log.info("微信商家转账异步通知返回解密参数 " + decryptToString);
            if (StringUtils.isBlank(decryptToString)) {
                throw new BusinessException("返回信息为空");
            }

            // 订单实体解析
            WechatTransferNotifyDecodeRequest transferNotifyDecodeRequest = JSONObject.parseObject(decryptToString, WechatTransferNotifyDecodeRequest.class);
            // 支付中状态不处理
            if (transferNotifyDecodeRequest.getBatchStatus().equals("FINISHED")
                || transferNotifyDecodeRequest.getBatchStatus().equals("CLOSED")) {
                transferNotifyDecodeRequest.setAppKey(appKey);
                transferCallbackManagerService.wechatNotify(transferNotifyDecodeRequest);
            }
            return Result.success();
        } catch (Exception e) {
            log.error("微信支付接口API,异步通知处理异常", e);
        }
        return Result.fail();
    }

    /**
     * 异步通知
     * @param mchId
     * @param request
     * @return
     */
    @PostMapping(value = "/refund/notify/{appKey}/{mchId}")
    public Result<Void> refundNotify(@PathVariable(name = "mchId") String mchId,
                                       @PathVariable(name = "appKey") String appKey,
                                       @RequestBody WechatPayNotifyOriginRequest request)  {
        try {
            log.info("微信退款异步通知返回原始参数 " + JSONObject.toJSONString(request));
            if (!"REFUND.SUCCESS".equalsIgnoreCase(request.getEventType())
                    && !"REFUND.ABNORMAL".equalsIgnoreCase(request.getEventType())
                    && !"REFUND.CLOSED".equalsIgnoreCase(request.getEventType())) {
                log.error("微信商家转账异步通知交易失败");
                return Result.success();
            }
            // 解密
            String apiV3Key = wechatPayClient.getApiV3Key();
            WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayNotifyOriginRequest.ResourceDto resource = request.getResource();
            String decryptToString = aesUtil.decryptToString(resource.getAssociatedData().getBytes(StandardCharsets.UTF_8), resource.getNonce().getBytes(StandardCharsets.UTF_8), resource.getCiphertext());
            log.info("微信商家退款异步通知返回解密参数 " + decryptToString);
            if (StringUtils.isBlank(decryptToString)) {
                throw new BusinessException("返回信息为空");
            }

            // 订单实体解析
            WechatRefundNotifyDecodeRequest refundNotifyDTO = JSONObject.parseObject(decryptToString, WechatRefundNotifyDecodeRequest.class);
            // 支付中状态不处理
            refundCallbackManagerService.refundNotify(refundNotifyDTO);
            return Result.success();
        } catch (Exception e) {
            log.error("微信支付接口API,异步通知处理异常", e);
        }
        return Result.fail();
    }
}
